using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;

using System.Windows.Forms;

using Darilek.SandcastleExtensions.Utilities;
using Darilek.SandcastleExtensions.Components.Configuration;

using Microsoft.Ddue.Tools;

namespace Darilek.SandcastleExtensions.Components
{
	/// <summary>
	/// Build component used for adding custom configured meta attributes into document header.
	/// </summary>
	/// <remarks>
	/// This component must be started at the end of build process
	/// (before last step - saving output into file).
	/// </remarks>
	public sealed class MetaAttributeComponent : BuildComponent
	{
		private List<KeyValuePair<string, string>> _attributesList = new List<KeyValuePair<string, string>>();

		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="assembler">>Reference to the build assembler</param>
		/// <param name="configuration">The configuration information</param>
		/// <exception cref="ConfigurationErrorsException">This is thrown if
		/// an error is detected in the configuration.</exception>
		public MetaAttributeComponent(BuildAssembler assembler, XPathNavigator configuration)
			: base(assembler, configuration)
		{

			base.WriteMessage(MessageLevel.Info, InfoHelper.GetFormattedInfo("Meta Attribute Component"));

			// read configuration
			XPathNodeIterator iterator = configuration.Select("attributes/attribute");
			XPathNavigator navigator;
			string attributeName;
			string attributeValue;

			while (iterator.MoveNext())
			{
				navigator = iterator.Current;
				attributeName = navigator.GetAttribute("name", String.Empty);
				attributeValue = navigator.GetAttribute("value", String.Empty);

				// check attributes
				if (String.IsNullOrEmpty(attributeName) || String.IsNullOrEmpty(attributeValue))
					throw new ConfigurationErrorsException("You must specify 'name' and 'value' attributes on the <attribute> element.");

				//_namespaceList.Add(attributeName, attributeValue);
				_attributesList.Add(new KeyValuePair<string, string>(attributeName, attributeValue));
			}
			base.WriteMessage(MessageLevel.Info, String.Format("Loaded {0} meta attribute definition(s)", _attributesList.Count));
		}

		#endregion

		#region Overrides

		/// <summary>
		/// Meta attributes inserting implementation
		/// </summary>
		/// <param name="document">The XML document with which to work.</param>
		/// <param name="key">The key (member name) of the item being
		/// documented.</param>
		public override void Apply(XmlDocument document, string key)
		{
			XmlNamespaceManager mgr = new XmlNamespaceManager(document.NameTable);
			XmlNode xmlNode;

			mgr.AddNamespace("MSHelp", "http://msdn.microsoft.com/mshelp");
			
			xmlNode = document.SelectSingleNode("/html/head/xml");
			if (xmlNode == null)
			{
				base.WriteMessage(MessageLevel.Warn, "<xml> element no found. Meta attributes cannot be added");
				return;
			}

			_attributesList.ForEach(delegate(KeyValuePair<string, string> keyValuePair)
				{
					XmlNode metaAttributeNode = document.CreateNode(XmlNodeType.Element, "MSHelp:Attr", mgr.LookupNamespace("MSHelp"));
					XmlAttribute metaName = document.CreateAttribute("Name");
					XmlAttribute metaValue = document.CreateAttribute("Value");
					metaName.Value = keyValuePair.Key;
					metaValue.Value = keyValuePair.Value;
					metaAttributeNode.Attributes.Append(metaName);
					metaAttributeNode.Attributes.Append(metaValue);

					xmlNode.AppendChild(metaAttributeNode);
				}
			);

		}

		#endregion

		#region Component configuration

		/// <summary>
		/// Configuration interface for Sandcastle Help File Builder (http://www/codeplex.com/shfb) tool
		/// </summary>
		/// <param name="currentConfig">Current component configuration</param>
		/// <returns>Modified component configuration</returns>
		public static string ConfigureComponent(string currentConfig)
		{
			using (MetaAttributeConfigDlg dlg = new MetaAttributeConfigDlg(currentConfig))
			{
				if (dlg.ShowDialog() == DialogResult.OK)
				{
					return dlg.Configuration;
				}
			}

			return currentConfig;
		}

		#endregion

	}
}
